class PyObject2HDFConverter:
    def __init__(self):
        pass
    
    def tohdf(self, root_path, object, hdf):
        return self._tohdf(hdf, root_path, object, {}, {})

    def tohdfNoRecursion(self, root_path, object, hdf):
        """this is a refactor function of tohdf without recursion."""
        return self._tohdfNoRecursion(hdf, root_path, object, {}, {})

    def check_recurse_info(self, object, recurse_info):
        object_id = str(id(object))
        if recurse_info.has_key(object_id):
            raise ("recursion loop! we got now %s, "
                              "original object %s" %
                              (object, recurse_info[object_id]))
        recurse_info[object_id] = object
        return object_id

    def _tohdf(self, hdf, root_path, object, recurse_info, hdf_dict):
        #check if this object is already converted, if so, create a
        #symlink instead of convert it again
        object_id = id(object)
        hdf_path = hdf_dict.get(object_id)
        if hdf_path is not None:
            if root_path.startswith('.'):
                root_path = root_path[1:]
            hdf.setSymLink(root_path, hdf_path)
            return hdf

        if isinstance(object, dict):
            self._convertDict(hdf, root_path, object, recurse_info, hdf_dict)
        elif isinstance(object, list):
            self._convertList(hdf, root_path, object, recurse_info, hdf_dict)
        elif isinstance(object, bool):
            self._convertSimple(hdf, root_path, int(object))
        elif isinstance(object, (str, int, float, long, unicode)):
            self._convertSimple(hdf, root_path, object)
        elif object is None:
            if root_path[0] == '.':
                root_path = root_path[1:]
            hdf.setValue(root_path, '')
        elif hasattr(object, '__str__'):
            self._convertSimple(hdf, root_path, str(object))
        else:
            raise ("Fail:%s" % object)

        if root_path.startswith('.'):
            root_path = root_path[1:]
        hdf_dict[object_id] = root_path
        return hdf

    def _tohdfNoRecursion(self, hdf, root_path, object, recurse_info, hdf_dict):
        """this is a refactor function of _tohdf without recursion.
        this can improve the performance greatly.
        """
        ## use obj_list as the stack for this no recursion function.
        obj_list = [[root_path, object]]
        while len(obj_list) > 0:
            obj_path, obj_item = obj_list.pop()
            #check if this obj_item is already converted, if so, create a
            #symlink instead of convert it again
            obj_item_id = id(obj_item)
            hdf_path = hdf_dict.get(obj_item_id)
            if hdf_path is not None:
                if obj_path.startswith('.'):
                    obj_path = obj_path[1:]
                hdf.setSymLink(obj_path, hdf_path)
                continue

            if isinstance(obj_item, dict):
                for key in obj_item.keys():
                    obj_list.insert(0,
                                    [obj_path + '.' + key, obj_item[key]])
            elif isinstance(obj_item, list):
                idx = 0
                while idx < len(obj_item):
                    item = obj_item[idx]
                    obj_list.insert(0,
                                    ['%s.%d' % (obj_path, idx), item])
                    idx += 1
            elif isinstance(obj_item, bool):
                self._convertSimple(hdf, obj_path, int(obj_item))
            elif isinstance(obj_item, (str, int, float, long, unicode)):
                self._convertSimple(hdf, obj_path, obj_item)
            elif obj_item is None:
                if obj_path[0] == '.':
                    obj_path = obj_path[1:]
                hdf.setValue(obj_path, '')
            elif hasattr(obj_item, '__str__'):
                self._convertSimple(hdf, obj_path, str(obj_item))
            else:
                raise ("Fail:%s" % obj_item)

            if obj_path.startswith('.'):
                obj_path = obj_path[1:]
            hdf_dict[obj_item_id] = obj_path

        return hdf

    def _convertDict(self, hdf, root_path, object, recurse_info, hdf_dict):
        object_id = self.check_recurse_info(object, recurse_info)
        for key in object.keys():
            self._tohdf(hdf, root_path + '.' + key, object[key],
                        recurse_info, hdf_dict)
        del recurse_info[object_id]

    def _convertList(self, hdf, root_path, object, recurse_info, hdf_dict):
        object_id = self.check_recurse_info(object, recurse_info)
        idx = 0
        for idx in range(len(object)):
            item = object[idx]
            self._tohdf(hdf, root_path + '.%d' % (idx,), item,
                        recurse_info, hdf_dict)
        del recurse_info[object_id]

    def _convertSimple(self, hdf, root_path, object):
        if root_path[0] == '.':
            root_path = root_path[1:]
        if isinstance(object, unicode):
            object = object.encode('utf8')
        converted = str(object)
        hdf.setValue(root_path, converted)
        ##print "%s = %s" % (root_path, converted)
